package pl.interop.logging;

import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.JRootPane;
import javax.swing.JTextArea;

/**
 * Implementacja Loggera jako singleton
 * @author Karol Piątek
 */
public class SimpleLogger {

    /**
     * Instacja klasy SimpleLogger
     */
    private static SimpleLogger instance;


	/**
	 * Klasa służąca do prezentacji komunikatów
	 * tymczasowo nie jest wykorzystywana
	 * TODO -
	 * zastąpienie standardowego Loggera z JRE/JDK ->
	 * www.slf4j.org
	 */
	private Logger loggerUtil;


    /**
     * Zmienna, w której będą przchowywane komunikaty dla końcowego użytkownika
     */
    private String msgForEndUser = "";

    /**
     * Zmienna określająca rozpoczęcia komunikatu dla developera,
     * wartość zmiennej widoczna tylko przez developera
     */
    private final String devMsgDesc = "dev msg \n\t";

    /**
     * Zmienna określająca rozpoczęcie komunikatu dla wystąpienia wyjątku,
     * wartość zmiennej widoczna tylko przez developera
     */
    private final String excMsgDesc = "exception msg \n\t";

    /**
     * Zmienna określająca rozpoczęcia komunikatu dla końcowego użytkownika
     * wartość zmiennej widoczna tylko przez developera
     */
    private String userFriendlyMsgDesc = "user-friendly msg \n\t";

    private Object guiObj;


	/**
	 * Prywatny konstruktor
	 * @param srcLogger
	 */
    private SimpleLogger(Logger srcLogger){
		this.loggerUtil = srcLogger;
	}


	/**
	 * Przesłoniona metoda clone,
	 * w przypadku używania wzorca Singleton
	 * nie wolno dopuścić, aby ta metoda zwróciła
	 * kopię obiektu
	 *
	 * @return Object
	 * @throws CloneNotSupportedException
	 */
    @Override
    public Object clone() throws CloneNotSupportedException {
		throw new CloneNotSupportedException("Nie wolno klonować obiektu " + SimpleLogger.class.getSimpleName());
    }

    /**
     * Pobranie instancji SimpleLogger
     * @return SimpleLogger
     */
    public static synchronized SimpleLogger getInstance(Logger srcLogger) {
        if(instance == null){
			instance = new SimpleLogger(srcLogger);
		}
        return instance;
    }

    /**
     * Metoda odpowiedzialana za przekazanie treści wiadomości,
     * która zostanie wyświetlona końcowemu użytkownikowi;
	 * 
     * wiadomosc zostaje przechowana w tymczasowej zmiennej,
     * a następnie jej wartość jest usuwana
     * i zwracana jest wartość zmiennej tymczasowej
     * @return String - informacja dla zwykłego użytkownika programu
     */
    public synchronized String getMsgForEndUser() {
        String destMsg = msgForEndUser;
        this.setMsgForEndUser("");
        return destMsg;
    }

    /**
     * Ustalenie obiektu, który ma zostać użyty do wyświetlania
     * komunikatów dla użytkownika
     * dla obiektow graficznych (np appletu)
     * nalezy wywolac setGuiUserMsg(this.rootPane)
     * @param guiPrompt
     */
    public synchronized void setGuiUserMsg(Object guiPrompt) {
        guiObj = guiPrompt;
    }

	/**
     * Pobranie obiektu, który ma zostać użyty do wyświetlania
     * komunikatów dla użytkownika
     * dla obiektow graficznych (np appletu)
     * nalezy wywolac setGuiUserMsg(this.rootPane)
	 * @return Object - zwraca obiekt. który ma zostać użyty do wyświetlania
     * komunikatów dla użytkownika
     */
    public synchronized Object getGuiUserMsg() {
        return guiObj;
    }

    /**
     * Wyświetla określony komunikat na standardowe wyjście
     * @param msg
     */
    public synchronized void echo(String msg) {
		if(msg != null){
			System.out.println(msg);
		}
    }

    /**
     * Metoda odpowiedzialna za określenie treści wiadomości dla użytkownika końcowego
     * jak i developera, używana jest w przypadku wystąpienia wyjątku,
     * osobno jest przekazywana treść wiadomości dla użytkownika końcowego i treść wyjątku,
     *
     * jezeli developer ustawi getStackTrace na true,
     * bedzie on wypisywany na standardowe wyjscie - w tym przypadku do logow serwera
     *
     * jako pierwszy parametr msgForUser należy umieścić pusty string lub komunikat,
     * który będzie widoczny dla developera
     * jako drugi parametr należy przekazać wyjątek,
     *
     * @param msgForUser
     * @param isDebug
     */
    public synchronized void echoDev(String msgForUser, Object ...isDebug) {
        if(msgForUser == null) {
			msgForUser ="";
		}

		setMsgForEndUser(msgForUser.toString());

        if(isDebug != null) {

            //znaczy, ze istnieja parametry dotyczace debuggowania
            if(isDebug.length > 0) {
                if(isDebug[0] != null) {
                    if(isDebug[0].getClass().getSimpleName().equalsIgnoreCase("String")) {
                        System.err.println(devMsgDesc + isDebug[0].toString());
                    }
                }

                //znaczy, ze możemy mieć do czynienia z wyjątkiem
                if(isDebug.length > 1) {

                    if(isDebug[1] !=null ) {
                        if(isDebug[1] instanceof Exception) {

                            Exception ex = ((Exception)isDebug[1]);
                            StringBuilder devMsg = new StringBuilder();
                            if(msgForUser.equalsIgnoreCase("")) {
								devMsg.append(excMsgDesc);
								devMsg.append(ex.getMessage());
							}
                            else {
								devMsg.append(userFriendlyMsgDesc);
								devMsg.append(msgForUser);
								devMsg.append("\n ");
								devMsg.append(excMsgDesc);
								devMsg.append(ex.getMessage());
							}
							System.err.println(devMsg);
                            ex.printStackTrace(System.err);
                        }
                    }
                }
            }
        }
    }

    /**
     * Metoda odpowiedzialna za określenie treści wiadomości dla użytkownika końcowego
     * jak i developera, używana jest w przypadku wystąpienia wyjątku,
     * osobno jest przekazywana treść wiadomości dla użytkownika końcowego i treść wyjątku,
	 *
     * jeżeli developer ustawi getStackTrace na true,
     * będzie on wypisywany na standardowe wyjście - w tym przypadku do logow serwera
     *
     * jako pierwszy parametr msgForUser
	 * należy umieścić pusty string lub komunikat, który będzie widoczny dla
	 * użytkownika końcowego,
	 * jako drugi parametr należy przekazać wyjątek,
     *
     * @param msgForUser
     * @param ex
     */
    public synchronized void echoDev(String msgForEndUser, Exception ex) {

        if(msgForEndUser == null) {
			msgForEndUser ="";
		}
        setMsgForEndUser(msgForEndUser.toString());
        if(ex != null) {
            StringBuilder devMsg = new StringBuilder();
            if(msgForEndUser.equalsIgnoreCase("")) {
				devMsg.append(excMsgDesc);
				devMsg.append(ex.getMessage());
			}
			else {
				devMsg.append(userFriendlyMsgDesc);
				devMsg.append(msgForEndUser);
				devMsg.append("\n ");
				devMsg.append(excMsgDesc);
				devMsg.append(ex.getMessage());
			}
            System.err.println(devMsg);
			devMsg = null;
            ex.printStackTrace(System.err);
        }
    }

    /**
     * Wyswietlenie komunikatu na standardowe wyjscie bledu
     * @param devMsg
     */
    public synchronized void echoDev(String devMsg){
        System.err.println(devMsg);
    }

    /**
     * Metoda odpowiedzialna za ustalenie treści wiadomości,
     * która zostanie wyświetlona końcowemu użytkownikowi
     * @param msgForUser
     */
    protected synchronized void setMsgForEndUser(String msgForEndUser) {

		//jezeli wiadomosc nie jest pusta, wyswietl ja
		if(!msgForEndUser.equalsIgnoreCase(""))
		{
			if(guiObj != null) {
				if(guiObj instanceof JRootPane ) {
					JOptionPane.showMessageDialog( (JRootPane)guiObj, msgForEndUser, "Powiadomienie",JOptionPane.INFORMATION_MESSAGE);
				}
				else if(guiObj instanceof JTextArea) {
					((JTextArea)guiObj).append(msgForEndUser);
					((JTextArea)guiObj).append("\n");
				}
			}
		}
        this.msgForEndUser = msgForEndUser;
    }
}
